package util

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"fmt"
)

// AesDecrypt AES数据解密
// @param encrypted string 密文
// @param key string 16字节密钥
// @param iv string 16字节初始向量
func AesDecrypt(encrypted, key, iv string) (string, error) {
	// 解码 base64 编码的加密数据
	encryptedBytes, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		return "", fmt.Errorf("base64解码错误: %v", err)
	}

	// 创建 AES 块
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", fmt.Errorf("创建AES块错误: %v", err)
	}

	// 检查 IV 长度是否正确
	if len(iv) != block.BlockSize() {
		return "", fmt.Errorf("IV长度错误: 需要 %d 字节，但得到 %d 字节", block.BlockSize(), len(iv))
	}

	// 检查加密数据长度是否是块大小的倍数
	if len(encryptedBytes)%block.BlockSize() != 0 {
		return "", fmt.Errorf("加密数据长度不是块大小的倍数: 需要 %d 字节的倍数，但得到 %d 字节", block.BlockSize(), len(encryptedBytes))
	}

	// 创建 CBC 模式的解密器
	mode := cipher.NewCBCDecrypter(block, []byte(iv))

	// 解密数据
	mode.CryptBlocks(encryptedBytes, encryptedBytes)

	// 去除填充
	plaintext, err := pkcs7Unpad(encryptedBytes, block.BlockSize())
	if err != nil {
		return "", fmt.Errorf("去除填充错误: %v", err)
	}

	return string(plaintext), nil
}

// pkcs7Unpad 去除 PKCS7 填充
func pkcs7Unpad(src []byte, blockSize int) ([]byte, error) {
	length := len(src)
	if length == 0 {
		return nil, fmt.Errorf("填充数据长度为0")
	}

	padding := int(src[length-1])
	if padding > blockSize || padding == 0 {
		return nil, fmt.Errorf("无效的填充")
	}

	for i := 0; i < padding; i++ {
		if src[length-i-1] != byte(padding) {
			return nil, fmt.Errorf("无效的填充")
		}
	}

	return src[:length-padding], nil
}

// Md5 计算给定字符串的 MD5 哈希值，并返回其十六进制表示。
func Md5(s string) string {
	// 创建一个新的 MD5 哈希器
	hasher := md5.New()
	// 将字符串的字节写入哈希器
	hasher.Write([]byte(s))
	// 计算哈希值，得到字节切片
	hashBytes := hasher.Sum(nil)
	// 将哈希值字节切片转换为十六进制字符串
	hashString := hex.EncodeToString(hashBytes)
	return hashString
}
